package com.fhc.view.echarts

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.view.View
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.fhc.view.utils.ToastyShow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okio.ByteString.Companion.decodeBase64
import org.json.JSONArray
import org.json.JSONObject
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream

enum class EChartsType() {
    Line,
    Scatter,
    LineScatter;
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun EChartsLineScatterWebView(context: Context, header: (@Composable () -> Unit)? = null, webViewHeight: Dp = 450.dp,
                              chartData: List<Triple<String, Double?, Double?>>,
                              onWebPageFinished:(WebView)->Unit={},
                              onChartImageGenerated:(String)->Unit={},
                              toImageTime:String = "") {
    val webViewRef = remember { mutableStateOf<WebView?>(null) }

    val clickedData = remember { mutableStateOf<String?>(null) }
    val longPressData = remember { mutableStateOf<String?>(null) }
    val toastState = remember { mutableStateOf<String?>(null) }

    // Show toast when message exists
    toastState.value?.let { message ->
        ToastyShow(msg = message){ }
        toastState.value = null
    }


    var chartHeight = 0f
    with(LocalDensity.current) {
        if(webViewHeight <= 0.dp) chartHeight =  450.dp.toPx()
        else chartHeight = webViewHeight.toPx()
    }


// 监听chartData变化
    LaunchedEffect(chartData) {
        if(webViewRef.value != null){
            updateChartWith2YData(webViewRef.value!!, chartData)
        }
    }
    LaunchedEffect(toImageTime) {
        if(webViewRef.value != null &&  toImageTime.isNotEmpty()) generateChartImage(context,webViewRef.value!!, onChartImageGenerated)
    }
    Box(modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(12.dp)).background(Color.White.copy(alpha = 0.15f))) {
        AndroidView(modifier = Modifier.padding(top = if(header != null) 20.dp else 0.dp).height(webViewHeight), factory = { ctx ->
            WebView(ctx).apply {
                setBackgroundColor(android.graphics.Color.TRANSPARENT)
                // 硬件加速
                setLayerType(View.LAYER_TYPE_HARDWARE, null)
                settings.apply {
                    cacheMode = WebSettings.LOAD_DEFAULT
                    domStorageEnabled = true
                }
                layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, chartHeight.toInt())
                webViewRef.value = this
                this.setLayerType(View.LAYER_TYPE_HARDWARE, null)  // 优先使用GPU渲染:ml-citation{ref="3,4" data="citationList"}

                settings.javaScriptEnabled = true
                webViewClient = object : WebViewClient() {
                    override fun onPageFinished(view: WebView, url: String) {
                        onWebPageFinished(view)
                    }
                }

                //将Java对象ChartClickHandler注入到WebView的JavaScript上下文，使网页脚本可通过指定名称调用该对象的方法
                // 参数1： 当JavaScript调用ChartHandler时触发该回调
                // 参数2： 定义JavaScript中访问该对象的全局变量名"ChartHandler"
                addJavascriptInterface(ChartEventHandler(
                    context = context,
                    jsEvent={evtName, params ->
                        if(evtName == JsEvent.CLICK) clickedData.value = "$evtName   name:${params.getString("name")} value:${params.getString("value")} "
                        else if(evtName == JsEvent.LONG_PRESS) longPressData.value = "$evtName     x:${params.getString("x")}  y:${params.getString("y")}"
                        toastState.value = "$evtName   name:${params.getString("name")} value:${params.getString("value")} "
                    },webError ={evtName, params ->
                        toastState.value = params
                    }
                ) , "ChartEventHandler")
                loadUrl("file:///android_asset/echarts/lineScatterChart.html")
            }
        },
            update = { webView ->
                updateChartWith2YData(webView, chartData)
            }
        )
        if(header != null) header()
    }


//    // 显示点击数据的UI
//    clickedData.value?.let { data ->
//        Text("点击数据: $data", color = Color.Red)
//    }
//    // 显示点击数据的UI
//    longPressData.value?.let { data ->
//        Text("LongPress: $data", color = Color.Red)
//    }

    DisposableEffect(Unit) {
        onDispose { webViewRef.value?.destroy() }
    }
}


@SuppressLint("SetJavaScriptEnabled")
@Composable
fun EChartsWebView(context: Context, header: (@Composable () -> Unit)? = null, webViewHeight: Dp = 450.dp,
                   chartData: List<Pair<String, Double>>,
                   onWebPageFinished:(WebView)->Unit={},
                   onChartImageGenerated:(String)->Unit={},
                   chartType:EChartsType = EChartsType.Line,
                   toImageTime: String = "") {
    val webViewRef = remember { mutableStateOf<WebView?>(null) }

    val clickedData = remember { mutableStateOf<String?>(null) }
    val longPressData = remember { mutableStateOf<String?>(null) }
    val toastState = remember { mutableStateOf<String?>(null) }

    // Show toast when message exists
    toastState.value?.let { message ->
        ToastyShow(msg = message){ }
        toastState.value = null
    }


    var chartHeight = 0f
    with(LocalDensity.current) {
        chartHeight = webViewHeight.toPx()
    }
// 监听chartData变化
    LaunchedEffect(chartData) {
        if(webViewRef.value != null) updateChart(webViewRef.value!!, chartData)
    }
    LaunchedEffect(toImageTime) {
        if(webViewRef.value != null &&  toImageTime.isNotEmpty()) generateChartImage(context, webViewRef.value!!, onChartImageGenerated)
    }
    Box(modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(12.dp)).background(Color.White.copy(alpha = 0.15f))) {
        AndroidView(modifier = Modifier.padding(top = if(header != null) 20.dp else 0.dp).height(webViewHeight), factory = { ctx ->
            WebView(ctx).apply {
                setBackgroundColor(android.graphics.Color.TRANSPARENT)
                // 硬件加速
                setLayerType(View.LAYER_TYPE_HARDWARE, null)
                settings.apply {
                    cacheMode = WebSettings.LOAD_DEFAULT
                    domStorageEnabled = true
                }
                layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, chartHeight.toInt())
                webViewRef.value = this
                this.setLayerType(View.LAYER_TYPE_HARDWARE, null)  // 优先使用GPU渲染:ml-citation{ref="3,4" data="citationList"}

                settings.javaScriptEnabled = true
                webViewClient = object : WebViewClient() {
                    override fun onPageFinished(view: WebView, url: String) {
//                            view.loadUrl("javascript:(function() { " +
//                                    "document.body.style.paddingTop = '${paddingTop}px';" +
//                                    "})()")

                        onWebPageFinished(view)
                    }
                }

                //将Java对象ChartClickHandler注入到WebView的JavaScript上下文，使网页脚本可通过指定名称调用该对象的方法
                // 参数1： 当JavaScript调用ChartHandler时触发该回调
                // 参数2： 定义JavaScript中访问该对象的全局变量名"ChartHandler"
                addJavascriptInterface(ChartEventHandler(
                    context = context,
                    jsEvent={evtName, params ->
                        if(evtName == JsEvent.CLICK) clickedData.value = "$evtName   name:${params.getString("name")} value:${params.getString("value")} "
                        else if(evtName == JsEvent.LONG_PRESS) longPressData.value = "$evtName     x:${params.getString("x")}  y:${params.getString("y")}"
                        toastState.value = "$evtName   name:${params.getString("name")} value:${params.getString("value")} "
                    },webError ={evtName, params ->
                        toastState.value = params
                    }
                ) , "ChartEventHandler")
                if(chartType == EChartsType.Scatter) loadUrl("file:///android_asset/echarts/dotChart.html")
                else if(chartType == EChartsType.Line) loadUrl("file:///android_asset/echarts/lineChart.html")
                else if(chartType == EChartsType.LineScatter) loadUrl("file:///android_asset/echarts/lineScatterChart.html")
            }
        },
            update = { webView ->
                // 复用WebView时更新数据
                updateChart(webView, chartData)
            }
        )
        if(header != null) header()
    }


//    // 显示点击数据的UI
//    clickedData.value?.let { data ->
//        Text("点击数据: $data", color = Color.Red)
//    }
//    // 显示点击数据的UI
//    longPressData.value?.let { data ->
//        Text("LongPress: $data", color = Color.Red)
//    }

    DisposableEffect(Unit) {
        onDispose { webViewRef.value?.destroy() }
    }
}




fun initChart(webView: WebView, data: List<Pair<String, Double>>) {
    val xData = JSONArray(data.map { it.first })
    val yData = JSONArray(data.map { it.second })
    webView.evaluateJavascript("""initChart( $xData, $yData )""".trimIndent(), null)
}
fun initChartWith2YData(webView: WebView, data: List<Triple<String, Double?, Double?>>) {
    if(data.isNotEmpty()) {
        val xData = JSONArray(data.map { it.first })
        val y1Data = JSONArray(data.map { it.second })
        val y2Data = JSONArray(data.map { it.third })
        webView.evaluateJavascript("""initChart( $xData, $y1Data, $y2Data )""".trimIndent(), null)
    }else {
        webView.evaluateJavascript("""initChart([], [], [])""".trimIndent(), null)
//        webView.evaluateJavascript("handleEmptyData()", null)
    }
}
fun updateChart(webView: WebView, data: List<Pair<String, Double>>) {
    val xData = JSONArray(data.map { it.first })
    val yData = JSONArray(data.map { it.second })
    webView.evaluateJavascript( "updateChart($xData, $yData)", null)
}
fun updateChartWith2YData(webView: WebView, data: List<Triple<String, Double?, Double?>>) {
    if(data.isNotEmpty()) {
        val xData = JSONArray(data.map { it.first })
        val y1Data = JSONArray(data.map { it.second })
        val y2Data = JSONArray(data.map { it.third })
        webView.evaluateJavascript("updateChart($xData, $y1Data, $y2Data)", null)
    }else {
        webView.evaluateJavascript("""initChart([], [], [])""".trimIndent(), null)
//        webView.evaluateJavascript("handleEmptyData()", null)
    }
}


fun generateChartImage(context: Context, webView: WebView, onChartImageGenerated:(String)->Unit={}) {
    webView.evaluateJavascript( "generateChartImage()") { imageData:String? ->
        //若 JavaScript 返回简单字符串（如 "result"），回调接收的 value 会包含双引号（"\"result\""），需去除转义字符：
        //当返回复杂对象（如 {data:123}）时，需使用 JSONObject 解析：
        imageData?.let { data: String ->
            val cleanedData = data.removeSurrounding("\"")
            saveEncodedToBitmap(context, cleanedData) { imgPath:String? ->
                imgPath?.let { path: String -> 
                    onChartImageGenerated(path) 
                }
            }
        }
        Timber.w("  generateChartImage  onReceiveValue   %s", imageData)
    }
}

// 创建一个专用的CoroutineScope用于处理后台任务
private val imageProcessingScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

fun saveEncodedToBitmap(context: Context, encodedImage: String, onSaved: (String?) -> Unit) {
    // 在后台线程处理图片解码和保存操作
    imageProcessingScope.launch {
        try {
            val base64String = encodedImage.replaceFirst("^data:image/.+;base64,".toRegex(), "")
            val byteString = base64String.decodeBase64() ?: throw IllegalArgumentException("Invalid Base64 input")
            val byteArray = byteString.toByteArray() // 将 ByteString 转换为 ByteArray
            val bitmap: Bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)

            // 4. 异步保存文件
            val filename = "chart_${System.currentTimeMillis()}.png"
            val file = File(context.filesDir, filename).apply {
                parentFile?.mkdirs()
            }

            FileOutputStream(file).use { out ->
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
            }
            
            // 回调到主线程通知保存完成
            withContext(Dispatchers.Main) {
                onSaved(file.absolutePath)
            }
        } catch (e: Exception) {
            Timber.e("  saveEncodedToBitmap        %s    %s", e.message,  encodedImage)
            // 回调到主线程通知保存失败
            withContext(Dispatchers.Main) {
                onSaved(null)
            }
        }
    }
}

private class ChartEventHandler(
    private val webError: (String, String) -> Unit,
    private val jsEvent: (JsEvent?, JSONObject) -> Unit,
    private val context: Context,
) {
    @Suppress("unused")
    @JavascriptInterface
    fun onEvent(eventName: String, params: String) {
        Timber.i("  onEvent   %s     %s", eventName, params)
        val evt = JsEvent.fromValue(eventName)
        if(evt != null) {
            val json = JSONObject(params)
            jsEvent(evt,json)
        }else{
            webError(eventName,params)
        }
    }

//    可以通过evaluateJavascript的回调函数获取图片数据，不一定要用html中以下js方式回调
//    if(window.ChartEventHandler) {
//        ChartEventHandler.onImageGenerated(imageData);
//    }
//    @Suppress("unused")
//    @JavascriptInterface
//    fun onImageGenerated(imageData: String) {
//        // 处理 base64 图片数据（如保存到文件或展示）
//        val bitmap = decodeBase64ToBitmap(imageData)
//        saveBitmap(context, bitmap) // 保存图片
//    }
}

enum class JsEvent(val value: String) {
    CLICK("click"),
    LONG_PRESS("longpress");
    companion object {
        fun fromValue(value: String): JsEvent? {
            return entries.find { it.value == value }
        }
    }
}


